"""
使用分布式进程实现分布式任务处理。

知识点：
    1.在Thread和Process中，应当优选Process，因为Process更稳定，而且Process可以分布到多台机器上，而Thread最多只能分布到同一台机器的多个CPU上。
    2.Python的multiprocessing模块不但支持多进程，其中managers子模块还支持把多进程分布到多台机器上。
      一个服务进程可以作为调度者，将任务分布到其他多个进程中，依靠网络通信。

特别提示：
    注意Queue的作用是用来传递任务和接收结果，每个任务的描述数据量要尽量小。
    比如发送一个处理日志文件的任务，就不要发送几百兆的日志文件本身，而是发送日志文件存放的完整路径，由Worker进程再去共享的磁盘上读取文件。
"""

import time
import queue

from multiprocessing.managers import BaseManager


class QueueManager(BaseManager):
    """
    队列管理
    """
    pass


# 由于这个QueueManager只从网络上获取Queue，所以注册时只提供名字。
QueueManager.register("get_task_queue")
QueueManager.register("get_result_queue")


def process_task(task_q, result_q):
    """
    处理任务任务
    """

    for i in range(100):
        try:
            n = task_q.get(timeout=10)
            print("执行任务：{n} * {n} ...".format(n=n))
            r = "{n} * {n} = {res}".format(n=n, res=n * n)
            time.sleep(1)
            result_q.put(r)
        except queue.Empty:
            print("队列为空")


def run():
    # 连接服务器（运行50_task_master.py的机器）
    server_addr = "127.0.0.1"
    print("连接服务器{server_addr}...".format(server_addr=server_addr))

    # 验证IP地址、端口和验证码
    manager = QueueManager(address=(server_addr, 8000), authkey=b"Admin123$")

    # 开始网络连接
    manager.connect()

    # 获得网络获取Queue对象
    task_q = manager.get_task_queue()
    result_q = manager.get_result_queue()

    # 处理任务并返回处理结果到队列中
    process_task(task_q=task_q, result_q=result_q)
    print("任务处理完成，worker退出")


if __name__ == "__main__":
    run()
